package com.twu.biblioteca;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class BibliotecaApp {
    private Scanner reader;
    private PrintStream printer;
    private SessionManager sessionManager;
    private Library library;
    private LibraryView libraryView;

    private enum MenuOption {
        LIST_BOOKS("List Available Books") {
            @Override
        public void runOption(LibraryView libraryView) {
                libraryView.displayAvailableBookList();
            }
        },
        CHECKOUT_BOOK("Checkout Book") {
            @Override
            public void runOption(LibraryView libraryView) {
                libraryView.checkoutBook();
            }
        },
        RETURN_BOOK("Return Book") {
            @Override
            public void runOption(LibraryView libraryView) {
                libraryView.returnBook();
            }
        },
        LIST_MOVIES("List Available Movies") {
            @Override
            public void runOption(LibraryView libraryView) {
                libraryView.displayAvailableMovieList();
            }
        },
        CHECKOUT_MOVIE("Checkout Movie") {
            @Override
            public void runOption(LibraryView libraryView) {
                libraryView.checkoutMovie();
            }
        },
        LOGIN("Login") {
            @Override
            public void runOption(LibraryView libraryView) {
                libraryView.login();
            }
        },
        USER_DETAILS("User Details", true) {
            @Override
            public void runOption(LibraryView libraryView) {
                libraryView.displayUserDetails();
            }
        },
        QUIT("Quit") {
            @Override
            public void runOption(LibraryView libraryView) {
            }
        };

        private final String message;
        private final boolean authenticationRequired;

        MenuOption(String message) {
            this(message, false);
        }

        MenuOption(String message, boolean authenticationRequired) {
            this.authenticationRequired = authenticationRequired;
            this.message = message;
        }

        String displayMessage() {
            return message;
        }

        boolean isAuthenticationRequired() {
            return authenticationRequired;
        }

        abstract void runOption(LibraryView libraryView);
    }

    public BibliotecaApp(InputStream in, OutputStream out) {
        this.reader = new Scanner(in);
        this.printer = new PrintStream(out);
        library = new Library();
        library.addBook(new Book("Head First Java", "Kathy Sierra", 2004));
        library.addBook(new Book("Test Driven Development: By Example", "Kent Beck", 2003));
        library.addBook(new Book("Effective Java", "Joshua Bloch", 2001));
        library.addMovie(new Movie("The Dark Knight", "Christopher Nolan", 9, 2008));
        library.addMovie(new Movie("Pulp Fiction", "Quentin Tarantino", 9, 1994));
        library.addMovie(new Movie("Frozen", "Chris Buck", null, 2013));
        sessionManager = new SessionManager();
        sessionManager.addUser(new User("123-1234", "Password", "James", "James@gmail.com", "0249576632"));
        libraryView = new LibraryView(reader, printer, library, sessionManager);
    }

    public void run() {
        printer.println("Welcome to the Bangalore Library Management System - Biblioteca");
        Map<Integer, MenuOption> availableMenuOptionMap = new HashMap<Integer, MenuOption>();
        MenuOption menuOption = null;
        while(menuOption != MenuOption.QUIT) {
            printer.println("Please select from one of the following options:");
            availableMenuOptionMap.clear();
            for(MenuOption currentMenuOption : MenuOption.values()) {
                if(!currentMenuOption.isAuthenticationRequired() || sessionManager.isAuthenticated()) {
                    int optionNumber = currentMenuOption.ordinal() + 1;
                    availableMenuOptionMap.put(optionNumber, currentMenuOption);
                    printer.println(optionNumber + ") " + currentMenuOption.displayMessage());
                }
            }

            int optionNumber = 0;
            if(reader.hasNextInt()) {
                optionNumber = reader.nextInt();
            } else if(reader.hasNext()) {
                reader.next();
            }

            menuOption = availableMenuOptionMap.get(optionNumber);
            if(menuOption != null) {
                menuOption.runOption(libraryView);
            } else {
                printer.println("Select a valid option!");
            }
        }
        printer.print("Thank you for using Biblioteca");
    }

    public static void main(String[] args) {
        new BibliotecaApp(System.in, System.out).run();
    }
}